Skip to content

[Feat]: Clean architecture#9

Merged
maksymhryzodub-prog merged 32 commits into
mainfrom
feat/clean-architecture
Jul 21, 2026
Merged

[Feat]: Clean architecture#9
maksymhryzodub-prog merged 32 commits into
mainfrom
feat/clean-architecture

Conversation

@maksymhryzodub-prog

Copy link
Copy Markdown
Contributor

No description provided.

maksymhryzodub-prog and others added 30 commits July 20, 2026 22:30
- Introduced a new chat slice with a comprehensive service layer, including `ChatGateway` and `ChatService` for managing chat sessions, messages, and feedback.
- Added UI components for chat history, message bubbles, and chat detail views, enhancing user interaction with chat transcripts.
- Implemented functionality for loading chat messages, providing feedback, and exporting chat transcripts in various formats (JSON, Markdown, CSV).
- Established a dependency injection plugin to provide the chat service throughout the application.

This update lays the groundwork for a robust chat feature, allowing users to view, interact with, and manage their chat history effectively.
Mirror the chat slice's layering: extract the agent-send into a domain
service + data gateway/mapper behind IBridleGateway, provided via a
$bridleService DI plugin. The store keeps its reactive conversation state
and localStorage persistence but no longer touches #api or unwrap.

Also relocate unwrapEnvelope from #chat/data to #common/data so every
slice's gateways share one envelope-peeling boundary (chat updated to
import it from #common).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply the same layering to the agent and auth slices: extract network
calls into domain services + data gateways/mappers behind IAgentGateway /
IAuthGateway, each provided via a DI plugin ($agentService / $authService).
Stores keep their reactive state (agent lists/current + loading/error;
auth token/user/hydration + localStorage + bearer wiring) but no longer
touch #api or unwrap.

Notes:
- agent remove(): pass the SDK-required query { wipeS3: 'false' }, which
  also fixes a pre-existing type error and keeps deletes non-destructive.
- SDK/domain name collision (both AuthService): the data gateway imports
  the SDK aliased as AuthApi.
- auth-init plugin now dependsOn 'auth-di' so $authService is provided
  before init() -> me() runs at setup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mposable layers

- Introduced a new error handling structure, including `ErrorEntity`, `ErrorMapper`, and `handleError` service for managing application errors.
- Added utility functions for error handling and toast notifications.
- Created composables for using error states in Vue components.
- Updated Nuxt configuration to support the new error slice.
- Established a clear separation of concerns between error data, domain logic, and UI components.

This update enhances the application's error management capabilities, providing a more robust and user-friendly experience.
- Introduced `AuthCommonForm` component for handling both login and registration forms, including validation and error handling.
- Created `Provider.vue` components for login and registration, integrating the common form and managing submission logic.
- Enhanced user experience with dynamic feedback during form submission and error display.

This update streamlines the authentication process, providing a unified interface for user login and registration.
Mirror the app's chat slice: extract the admin chat API into a domain
service + data gateway/mapper behind IChatGateway, provided via a
$chatService DI plugin. The store becomes a thin facade and no longer
touches #api or unwrap. Adds the admin's own #common infra (BaseGateway,
createServiceGetter, unwrapEnvelope).

Admin specifics vs the app: list filters (IChatListQuery), on-demand
summarize (keeps throwIfError for now), 6-role transcript incl. tool/system
events, and IChatSession carrying agentId + summaryAt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…for ranch

Adopt the shared #error error-handling system in the admin chat gateway:
inject ErrorMapper via BaseGateway's super() and set throwOnError on
summarizeChat so failures flow through the mapper (replaces the ad-hoc
throwIfError helper) and surface as a typed ErrorEntity.

Fix the ErrorMapper (both app + admin, ported from main-site's ofetch +
FastAPI stack) for ranch's axios client + NestJS API:
- read the error body from response.data (axios), not just response._data
  (ofetch); _data keeps precedence for compatibility.
- surface NestJS's human-readable `message` verbatim when there's no
  FastAPI-style `detail`, instead of collapsing to a generic key.

Brings the admin's #error slice under version control.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate both stores of the agent/agent slice:

- agent.ts (CRUD + lifecycle): extract behind IAgentGateway + AgentService,
  hiding the mixed transport (generated SDK, raw axios for stop/start/env/
  metrics, raw fetch for the wipeS3 delete) and the rich failure handling
  (unwrapOrThrow) in the data layer. The store keeps the reactive agent list,
  optimistic status flips, and the localStorage restart flags. Also fixes a
  latent type error: logControllerGetLogs requires a `tail` query param.

- agentStatus.ts (live SSE stream): follow main-site's subscription pattern
  (profileSubscription). The data gateway owns the EventSource and decodes
  frames via a mapper; the store keeps state + the reducer + consumer
  ref-counting. Provided as $agentStatusService alongside $agentService.

Adds the agent slice's DI plugin + NuxtApp augmentation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the agent-channels API behind IAgentChannelGateway + AgentChannel
service (provided as $agentChannelService); the store keeps only the
per-agent cache + synchronous getCached. DTO mapping and envelope
unwrapping move to the data layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the agent-secrets API behind IAgentSecretGateway + AgentSecret
service ($agentSecretService). Mutations return the refreshed list and
throw the API's message on failure (moved into the gateway); the store
keeps the reactive data/loading/error state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the agent file-workspace API behind IAgentFileGateway + AgentFile
service ($agentFileService), including the raw-fetch ZIP export (gateway
returns the Blob; the store triggers the download). The store keeps the
reactive tree, the localStorage restart flags, and the save/delete node
patching.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the templates API behind ITemplateGateway + TemplateService
($templateService): CRUD, setSkills/setMcps, and restartAgents (which
hits the agent controller server-side, kept here so the store stays
SDK-free). The store keeps the reactive list + mutations. Mapper converts
the ITemplateResources interface to the DTO's index-signature shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the template file-workspace API behind ITemplateFileGateway +
TemplateFile service ($templateFileService); the upload's folder-path
derivation (webkitRelativePath) moves into the gateway. The store keeps
the reactive tree + save node patching.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract template install (ZIP + git) behind ITemplateInstallGateway +
TemplateInstall service ($templateInstallService). All transport moves to
the gateway: raw multipart fetch for the archive endpoints (the SDK drops
FormData), the SDK for git, plus the error handling. The store had no
reactive state, so it's now a thin facade.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the LLM-credentials API behind ILlmGateway + LlmService
($llmService). The store keeps the reactive list/loading/error. Mapper
coerces the domain's free `status: string` to the DTO's active|disabled
union (fixes a latent type error). Static data/providers.ts is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the MCP-servers API behind IMcpServerGateway + McpServerService
($mcpServerService). The store keeps the reactive list + mutations. Mapper
coerces the generator-mistyped description/authValue (typed as objects,
really nullable strings) at the DTO boundary.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the integration-sessions API behind ISessionGateway +
SessionService ($sessionService). The gateway uses the low-level SDK
client (endpoints aren't in the generated SDK); the browser-mechanism
filter moves into the service. The store keeps list/loading/error.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the settings API behind ISettingGateway + SettingService
($settingService). The store keeps the reactive list plus the synchronous
get/getValue lookups. Mapper casts the domain's `value: unknown` past the
generator-mistyped DTO value field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the skills API behind ISkillGateway + SkillService ($skillService):
CRUD, search, import from github/url, and dependent-agents lookup. The
store keeps list/loading/error + the placeImported cache helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the per-agent usage API behind IUsageGateway + UsageService
($usageService). The store keeps the per-agent cache + synchronous
getForAgent. SDK class aliased as UsageApi to avoid the name collision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the users API behind IUserGateway + UserService ($userService):
CRUD + updateRoles. The store keeps the reactive list + mutations. Mapper
casts the domain role/status enums past the generated wire enums (same
values, different TS identity).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the API-keys API behind IApiKeyGateway + ApiKeyService
($apiKeyService). The store keeps list/loading/error + the created-key
unshift. Mapper casts the domain scope enum past the wire enum.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract admin login/me behind IAuthGateway + AuthService ($authService);
the SDK class of the same name is aliased AuthApi in the gateway. The store
keeps the cookie-backed token, user, computeds, and the bearer wiring. The
auth-init plugin now dependsOn 'auth-di' so $authService exists before
hydrate() -> me() runs at setup.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the Rancher bootstrap-status API behind IRancherGateway +
RancherService ($rancherService). The store keeps the reactive status and
patches the template in after ensureTemplate. SDK class aliased RancherApi.
Domain reuses IAgentData/ITemplateData from the agent/template domains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrate both paddock stores behind gateways + services:
- paddockEvaluation → IPaddockEvaluationGateway + PaddockEvaluationService
  ($paddockEvaluationService): list/get/start/abort/rerun/report/trace, plus
  the raw-client logs/evalScenario routes.
- paddockScenario → IPaddockScenarioGateway + PaddockScenarioService
  ($paddockScenarioService): CRUD + generate.
Both provided from one DI plugin. Evaluations/scenarios are deeply nested
opaque structures, so mappers are presence-validated casts. Stores keep the
reactive lists + mutations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the knowledge-bases API behind IKnowledgeGateway + KnowledgeService
($knowledgeService): CRUD, index, query, graph, and the source operations
(text/url/file/archive/sitemap — multipart via the raw axios instance, plus
the raw-client /status route). The store keeps the reactive list +
status/setup flags and composes startIndex. Mappers validate entities
defensively; the opaque query-result/graph DTOs stay as #api passthroughs
in the domain (documented exception).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cleaned up the Provider.vue component by removing unnecessary imports for Badge, Button, Input, Label, and Textarea, streamlining the code for better readability and performance.
- auth gateway: set throwOnError on login/me so a 401 propagates (as the
  axios error) instead of the client silently yielding an empty session;
  the login Provider's catch then shows the API's message ("Invalid
  credentials"). Also lets hydrate() clear a stale/expired token.
- auth Form: add a show/hide password eye toggle and render the error as a
  proper destructive alert box (matches the app's login form).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an axios response interceptor: on a 401 for any non-auth endpoint
(expired / missing token, e.g. "Missing access token"), reset auth state
via the store's logout() and redirect to /login. Login/register 401s are
credential errors surfaced inline on the form, so those are excluded.
logout() clears the store ref (not just the cookie) so the auth middleware
sees "not authenticated" and doesn't bounce /login back to /agents.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cleaned up the Form.vue component by removing unnecessary imports for Button, Input, Label, and Card components, enhancing code readability and maintainability.
maksymhryzodub-prog and others added 2 commits July 21, 2026 14:57
Mirror the admin's response interceptor: on a 401 for a non-auth endpoint
(expired / missing token), reset auth state via the store's logout() and
redirect to /login. All /auth/* endpoints are excluded — a login 401 is a
credential error shown inline, and an init() /auth/me 401 is cleared
silently by the auth store, so a returning visitor with a stale token still
lands on the public pages (logged out) instead of being bounced to /login.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the app's token persistence from localStorage ('ranch.access_token')
to a 7-day, JS-readable `access_token` cookie via useCookie — same
convention as the admin. The Bearer header is still attached through
handleApiAuthentication; only the persistence layer changed. init() now
restores from the cookie-backed accessToken ref.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maksymhryzodub-prog
maksymhryzodub-prog merged commit 6e0b285 into main Jul 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant